// Copyright (c) 2010 http://xbeeservice.codeplex.com
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.html
// All other rights reserved.

using System;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.Core.DsspHttp;
using Microsoft.Dss.ServiceModel.Dssp;
using W3C.Soap;

namespace SoCGadget.Robotics.XBee
{
    /// <summary>
    /// XBeeService contract class
    /// </summary>
    public sealed class Contract
    {
        /// <summary>
        /// DSS contract identifer for XBeeService
        /// </summary>
        [DataMember]
        public const string Identifier = "http://schemas.socgadget.com/2010/05/xbeeservice.html";
    }

    /// <summary>
    /// Represents a 64-bit network address. Use the serial number of the destination device.
    /// </summary>
    [DataContract]
    [DisplayName( "XBee 64-bit network address" )]
    [Description( "XBee 64-bit network address" )]
    public class XBeeAddress64
    {
        [DataMember]
        public UInt32 AddressHigh;

        [DataMember]
        public UInt32 AddressLow;

        internal UInt64 Address64Bit
        {
            get
            {
                return ( ( UInt64 )AddressHigh << 32 | AddressLow );
            }
        }

        /// <summary>
        /// For 64-bit addressing, 16-bit source address is disabled by setting it to 0xFFFE (MY param).
        /// </summary>
        internal UInt16 Address16Bit = 0xFFFE;
    }

    #region Get

    /// <summary>
    /// XBeeService state
    /// </summary>
    [DataContract]
    public class XBeeServiceState
    {
        [DataMember]
        public int Baud { get; set; }

        [DataMember]
        public string ApiMode { get; set; }

        [DataMember]
        public string SerialPort { get; set; }

        [DataMember]
        public bool IsConnected { get; set; }
    }
	
    /// <summary>
    /// XBeeService get operation
    /// </summary>
    public class Get : Get<GetRequestType, PortSet<XBeeServiceState, Fault>>
    {
    /// <summary>
        /// Creates a new instance of Get
        /// </summary>
        public Get()
        {
        }
		
        /// <summary>
        /// Creates a new instance of Get
        /// </summary>
        /// <param name="body">the request message body</param>
        public Get(GetRequestType body)
            : base(body)
        {
        }
		
        /// <summary>
        /// Creates a new instance of Get
        /// </summary>
        /// <param name="body">the request message body</param>
        /// <param name="responsePort">the response port for the request</param>
        public Get(GetRequestType body, PortSet<XBeeServiceState, Fault> responsePort)
            : base(body, responsePort)
        {
        }
    }

    #endregion

    #region Connect

    /// <summary>
    /// Connection information for the controller we want to connect to.
    /// </summary>
    [DataContract]
    public class ConnectRequest
    {
        /// <summary>
        /// Serial port baud rate to communicate with the host XBee device.
        /// Typically 9600
        /// </summary>
        [DataMember]
        public int Baud { get; set; }

        /// <summary>
        /// API mode for the XBee. Supported values are
        ///     ApiOperation
        ///     ApiOperationEscaped
        /// </summary>
        [DataMember]
        public string ApiMode { get; set; }

        /// <summary>
        /// Serial port the host XBee device is connected to. Specified in the format "COMx"
        /// where x is the port number. Leave as empty string to allow the service to search
        /// for the XBee device.
        /// </summary>
        [DataMember]
        public string SerialPort { get; set; }
    }

    /// <summary>
    /// Updates the conntection state of the controller.
    /// </summary>
    public class Connect : Update<ConnectRequest, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public Connect() :
            base( new ConnectRequest() )
        {
        }

        public Connect( ConnectRequest request ) :
            base( request )
        {
        }
    }

    #endregion

    #region Disconnect

    /// <summary>
    /// Disconnect information.
    /// </summary>
    [DataContract]
    public class DisconnectRequest
    {
    }

    /// <summary>
    /// Updates the conntection state of the controller.
    /// </summary>
    public class Disconnect : Update<DisconnectRequest, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public Disconnect() :
            base( new DisconnectRequest() )
        {
        }
    }

    #endregion

    #region DeviceMessageUpdate

    /// <summary>
    /// Data contract representing a message to send to a device.
    /// </summary>
    [DataContract]
    [DisplayName( "XBee service device message state" )]
    [Description( "XBee service device message state" )]
    public class DeviceMessage
    {
        /// <summary>
        /// The string message that gets sent to the end device.
        /// </summary>
        [DataMember]
        public string Message { get; set; }

        /// <summary>
        /// The 64-bit network address of the destination end device. This will be the serial
        /// number of that end device.
        /// </summary>
        [DataMember]
        public XBeeAddress64 DestinationAddress { get; set; }
    }

    /// <summary>
    /// Send a message to an XBee device
    /// </summary>
    public class DeviceMessageUpdate : Update<DeviceMessage, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public DeviceMessageUpdate()
            : base( new DeviceMessage() )
        {
        }

        public DeviceMessageUpdate( DeviceMessage state )
            : base( state )
        {
        }

        public DeviceMessageUpdate( DeviceMessage state, PortSet<DefaultUpdateResponseType, Fault> responsePort )
            : base( state, responsePort )
        {
        }
    }

    #endregion

    #region DataSampleUpdate

    /// <summary>
    /// A simplified type for the digital IO of the Xbee device.
    /// </summary>
    [DataContract]
    [DisplayName( "XBee device digital data" )]
    [Description( "XBee device digital data" )]
    public class DigitalData
    {
        public DigitalData() { }

        public DigitalData( uint size, ushort sample )
        {
            if ( size == 0 || size > sizeof( ushort )*8 )
                throw new ArgumentException( "size parameter out of range." );

            Raw = sample;
            int i = 0;

            DIO = new bool[ size ];

            while ( i < size && sample > 0 )
            {
                DIO[ i++ ] = ( sample & 0x01 ) > 0;
                sample >>= 1;
            }
        }

        [DataMember]
        public bool[] DIO { get; set; }

        [DataMember]
        public ushort Raw { get; set; }
    }

    /// <summary>
    /// Represents a data sample from an xbee device
    /// </summary>
    [DataContract]
    [DisplayName( "XBee device data sample" )]
    [Description( "XBee device data sample" )]
    public class DataSample
    {
        [DataMember]
        public ulong SourceSerialNumber { get; set; }

        [DataMember]
        public ushort SourceAddress { get; set; }

        [DataMember]
        public DigitalData DigitalChannelMask { get; set; }

        [DataMember]
        public DigitalData DigitalIO { get; set; }

        [DataMember]
        public DigitalData AnalogChannelMask { get; set; }

        [DataMember]
        public ushort[] AnalogIO { get; set; }

        /// <summary>
        /// Supply voltage read by the XBee device, in millivolts.
        /// Value is 0 if no supply voltage sample was sent.
        /// </summary>
        [DataMember]
        public ushort SupplyVoltage { get; set; }
    }

    /// <summary>
    /// Data sample received from an XBee device
    /// </summary>
    public class DataSampleUpdate : Update<DataSample, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public DataSampleUpdate()
            : base( new DataSample() )
        {
        }

        public DataSampleUpdate( DataSample state )
            : base( state )
        {
        }

        public DataSampleUpdate( DataSample state, PortSet<DefaultUpdateResponseType, Fault> responsePort )
            : base( state, responsePort )
        {
        }
    }

    #endregion

    #region Remote Digital Output Command Update

    /// <summary>
    /// Data contract used for sending a remote DIO command to a device in order to update a
    /// digital output.
    /// </summary>
    [DataContract]
    [DisplayName( "XBee service remote digital output command state" )]
    [Description( "XBee service remote digital output command state" )]
    public class DeviceOutput
    {
        /// <summary>
        /// The 64-bit network address of the destination end device. This will be the serial
        /// number of that end device.
        /// </summary>
        [DataMember]
        public XBeeAddress64 DestinationAddress { get; set; }

        [DataMember]
        public byte OutputNumber;

        [DataMember]
        public bool OutputState;
    }

    /// <summary>
    /// Send a digital output update message to an XBee device
    /// </summary>
    public class DeviceOutputUpdate : Update<DeviceOutput, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public DeviceOutputUpdate()
            : base( new DeviceOutput() )
        {
        }

        public DeviceOutputUpdate( DeviceOutput state )
            : base( state )
        {
        }

        public DeviceOutputUpdate( DeviceOutput state, PortSet<DefaultUpdateResponseType, Fault> responsePort )
            : base( state, responsePort )
        {
        }
    }

    #endregion

    #region Subscribe

    /// <summary>
    /// XBeeService subscribe operation
    /// </summary>
    public class Subscribe : Subscribe<SubscribeRequestType, PortSet<SubscribeResponseType, Fault>>
    {
        /// <summary>
        /// Creates a new instance of Subscribe
        /// </summary>
        public Subscribe()
        {
        }
		
        /// <summary>
        /// Creates a new instance of Subscribe
        /// </summary>
        /// <param name="body">the request message body</param>
        public Subscribe(SubscribeRequestType body)
            : base(body)
        {
        }
		
        /// <summary>
        /// Creates a new instance of Subscribe
        /// </summary>
        /// <param name="body">the request message body</param>
        /// <param name="responsePort">the response port for the request</param>
        public Subscribe(SubscribeRequestType body, PortSet<SubscribeResponseType, Fault> responsePort)
            : base(body, responsePort)
        {
        }
    }

    #endregion

    /// <summary>
    /// XBeeService main operations port
    /// </summary>
    [ServicePort]
    public class XBeeServiceOperations : PortSet<
        DsspDefaultLookup,
        DsspDefaultDrop,
        Connect,
        Disconnect,
        Get,
        HttpGet,
        DeviceMessageUpdate,
        DataSampleUpdate,
        DeviceOutputUpdate,
        Subscribe>
    {
    }
}

